﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using TestModelFirst.Entities;

namespace TestModelFirst
{
    static class Tests
    {
        // ######################################################### //
        #region helpers

        private static void Print(this Blog blog)
        {
            Console.WriteLine("Blog<{0}> '{1}'", blog.Id, blog.Title);

            int postIndex = 0;
            foreach (var post in blog.Posts)
            {
                ++postIndex;
                Console.WriteLine("\t[{0}] Post<{1}> '{2}'", postIndex, post.Id, post.Title);

                int commentIndex = 0;
                foreach (var comment in post.Comments)
                {
                    ++commentIndex;
                    Console.WriteLine("\t\t[{0}] Comment<{1}>", commentIndex, comment.Id);
                }// foreach comment
            }// foreach post
        }

        private static Post NewPost(string title, string content)
        {
            return new Post
            {
                Title = title,
                DateCreated = DateTime.Now,
                Content = content
            };
        }

        private static Comment NewComment(string content)
        {
            return new Comment { DataCreated = DateTime.Now, Content = content };
        }

        private static void SaveAndReport(this BlogModelContainer db)
        {
            int changed = db.SaveChanges();
            Console.WriteLine("{0} rows affected", changed);
        }

        private static void MarkState<T>(this DbContext context, IEnumerable<T> entities, EntityState state) where T : class
        {
            foreach (T entity in entities)
            {
                context.Entry(entity).State = state;
            }
        }

        #endregion

        // ######################################################### //
        #region CRUD

        private static void Add()
        {
            using (var db = new BlogModelContainer())
            {
                var blog = new Blog { Title = "Test", Owner = "Me" };
                db.Blogs.Add(blog);

                var post = NewPost("first", "hello EF");
                // chekanote: this child entity is only need to be inserted into its parent
                // and it don't need to be added into the db explicitly
                // and it can still be inserted into the database successfully
                // db.Posts.Add(post);// chekanote: optional
                blog.Posts.Add(post);

                var comment = NewComment("well done");
                post.Comments.Add(comment);

                db.SaveAndReport();
            }
        }

        private static void Update()
        {
            using (var db = new BlogModelContainer())
            {
                var blog = db.Blogs.Find(4);
                blog.Title = "NewTitle";

                blog.Posts.First().Comments.Add(NewComment("just ok"));

                var newPost = NewPost("third", "test update");
                newPost.Comments.Add(NewComment("not bad"));
                blog.Posts.Add(newPost);

                db.SaveAndReport();
            }// using
        }

        private static void Navigate()
        {
            using (var db = new BlogModelContainer())
            {
                var infos = from p in db.Posts
                            select new { Blog = p.Blog.Title, p.Title };

                int index = 0;
                foreach (var info in infos)
                {
                    ++index;
                    Console.WriteLine("[{0}] Post<{1}> from Blog<{2}>", index, info.Title, info.Blog);
                }
            }
        }

        // chekanote: we have to manually delete children entities
        private static void Delete()
        {
            using (var db = new BlogModelContainer())
            {
                const int blogId = 1;
                var blog = db.Blogs.Find(blogId);
                db.MarkState(Enumerable.Repeat(blog, 1), EntityState.Deleted);

                var comments = from p in db.Posts
                               from c in db.Comments
                               where (p.BlogId == blogId) && (c.PostId == p.Id)
                               select c;
                db.MarkState(comments, EntityState.Deleted);

                var posts = from p in db.Posts
                            where p.BlogId == blogId
                            select p;
                db.MarkState(posts, EntityState.Deleted);

                db.SaveAndReport();
            }//using
        }

        #endregion

        public static void TestMain()
        {
            // Update();
            Navigate();
            // Delete();
        }
    }// Tests
}
